package interp;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import pars.Tree;
import scoping.Checker;
import scoping.helpers.SemanticCheckerResponse;
import ic.ast.decl.DeclClass;
import ic.ast.decl.DeclMethod;
import ic.ast.decl.Parameter;
import ic.ast.decl.PrimitiveType;
import ic.ast.decl.Program;
import ic.ast.decl.Type;

public class Interpreter {
		
	public void getClassAndMethod(Tree ast,String className,String methodName,List<String> arguments){
		Checker checker = new Checker();
		SemanticCheckerResponse response = checker.check(ast,false);
		boolean interpreted=false;
		if(!(response.is_isValid())){ // if the program has semantic errors, throw runtime error 
			throw new RuntimeError("Runtime Error");
		}
		
		for (Tree class_tree:ast.subtrees){
			if(class_tree.root instanceof DeclClass){
				if(((DeclClass)class_tree.root).getName().equals(className)){
					for(Tree function_tree:class_tree.subtrees){
						if(function_tree.root instanceof DeclMethod){
							if(((DeclMethod)function_tree.root).getName().equals(methodName)){
								Initalize_Params_and_Invoke_Interpreter((DeclMethod)(function_tree.root),arguments);
								interpreted=true;
							}
						}
					}
				}
			}
		}
		if(interpreted==false){
			throw new RuntimeError("Couldn't find class/method");
		}
		
	}
	

	public Interpreter(Tree ast, String[] args) {
		String className=null;
		String methodName=null;
		List<String> arguments=new ArrayList<String>();
		boolean parsedClassAndMethod=false;
		for(int i=1;i<args.length;i++){  //ignore the first argument which is filename
			if(i==1){
				if(args[i].startsWith("-L")){ //IGNORE
					continue;
				}
				else{
					String[] tokens=args[1].split("\\.");
					className=tokens[0];
					methodName=tokens[1];
					parsedClassAndMethod=true;
				}
			}
			else{
				if(parsedClassAndMethod==false){
					String[] tokens=args[i].split(".");
					className=tokens[0];
					methodName=tokens[1];
					parsedClassAndMethod=true;
				}
				else{
					arguments.add(args[i]);
				}
			}
		}
		getClassAndMethod(ast,className,methodName,arguments);
	}


	private void Initalize_Params_and_Invoke_Interpreter(DeclMethod declMethod,List<String> arguments) {
		HashMap<String,Object> vars=new HashMap<String,Object>();
		int i=0;
		if(arguments.size() != declMethod.getFormals().size()){
			throw new RuntimeError("The number of arguments does not match the number of parameters");
		}
		for(Parameter param:declMethod.getFormals()){
			if (param.getType().getDisplayName().equals("int")){
				try{
					vars.put(param.getName(),Integer.parseInt(arguments.get(i)));
				}
				catch (NumberFormatException nfe){
					throw new RuntimeError("Argument is not a an integer");
				}
				
			}
			else if(param.getType().getDisplayName().equals("string")){
				vars.put(param.getName(),arguments.get(i));
			}
			i++;
		}
		InterpertVisitor intr_vis=new InterpertVisitor(declMethod, vars);		
	}

}
